package com.gdou.teaching.service.impl;

import com.gdou.teaching.Enum.ExperimentStatusEnum;
import com.gdou.teaching.Enum.FileCategoryEnum;
import com.gdou.teaching.Enum.RecordStatusEnum;
import com.gdou.teaching.Enum.ResultEnum;
import com.gdou.teaching.constant.RedisConstant;
import com.gdou.teaching.dataobject.Clazz;
import com.gdou.teaching.dataobject.ExperimentMaster;
import com.gdou.teaching.dataobject.Record;
import com.gdou.teaching.dto.FileDTO;
import com.gdou.teaching.dto.RecordDTO;
import com.gdou.teaching.exception.TeachingException;
import com.gdou.teaching.mapper.AchievementMapper;
import com.gdou.teaching.mapper.ExperimentDetailMapper;
import com.gdou.teaching.mapper.ExperimentMasterMapper;
import com.gdou.teaching.mapper.UserReExperimentMapper;
import com.gdou.teaching.service.ExperimentService;
import com.gdou.teaching.service.FileService;
import com.gdou.teaching.service.RecordService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author bo
 * @date Created in 16:36 2019/9/12
 * @description
 **/
@Service
@Slf4j
public class RecordServiceImpl implements RecordService {
    @Autowired
    ExperimentMasterMapper experimentMasterMapper;
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    UserReExperimentMapper userReExperimentMapper;
    @Autowired
    AchievementMapper achievementMapper;
    @Autowired
    ExperimentService experimentService;
    @Autowired
    FileService fileService;


    @Override
    public RecordDTO save(RecordDTO recordDTO) {
        Record record = new Record();
        BeanUtils.copyProperties(recordDTO,record);

        //查询该实验的状态。
        ExperimentMaster experiment = experimentMasterMapper.selectExperimentMasterByExperimentId(record.getExperimentId());
        if (experiment.getExperimentStatus()!=ExperimentStatusEnum.NORMAL.getCode()){
            log.error("保存纪录,保存实验记录失败,当前实验不可提交,ExperimentStatus={}",experiment.getExperimentStatus());
            throw new TeachingException(ResultEnum.EXPERIMENT_STATUS_ERROR);
        }
        //查询上一次提交的状态。
        Record preRecord = userReExperimentMapper.selectUserReExperimentByExperimentIdAndUserId(recordDTO.getExperimentId(), recordDTO.getUserId());
        Integer preStatus = preRecord.getStatus();
        if(preStatus==RecordStatusEnum.PASS.getCode()||preStatus==RecordStatusEnum.LOCK.getCode()){
            //如果已经通过审核或者是实验被锁定，无法再次提交
            log.error("保存实验记录失败,已有实验提交记录被审核通过或实验已被锁定,preStatus={}",preStatus);
            throw new TeachingException(ResultEnum.SUBMIT_RECORD_ERROR);
        }
        //TODO 将上次的记录设置为作废。考虑是否要完成
        //进行提交。
        record.setExperimentAchievement((double)0);
        record.setStatus(RecordStatusEnum.REVIEWING.getCode());
        Integer i = userReExperimentMapper.addUserReExperiment(record);
        if (i<=0){
            log.error("保存记录,保存实验记录失败,record={}",record);
            throw new TeachingException(ResultEnum.SUBMIT_RECORD_ERROR);
        }
        //存储文件
        List<FileDTO> fileDTOs = recordDTO.getUserExperimentFile();
        fileService.saveFile(FileCategoryEnum.RECORD_FILE.getCode(), record.getUserExperimentId(), fileDTOs);
        return recordDTO;
    }


    //todo 缺少ExperimentName
    @Override
    public RecordDTO selectOne(Integer experimentId,Integer userId) {
        Record one = userReExperimentMapper.selectUserReExperimentByExperimentIdAndUserId(experimentId, userId);
        if (one==null){
        //            log.error("查询提交记录,找不到提交记录");
        // throw new TeachingException(ResultEnum.PARAM_ERROR);
            //修改逻辑以适应前台，如果找不到,说明没提交，无需处理。
            return null;
        }
        RecordDTO recordDTO = new RecordDTO();
        //查询用户提交时提交的文件记录
        List<FileDTO> fileDTOList = fileService.selectFileByCategoryAndFileCategoryId(FileCategoryEnum.RECORD_FILE.getCode(), one.getUserExperimentId());
        if(!fileDTOList.isEmpty()){
            recordDTO.setUserExperimentFile(fileDTOList);
        }
        BeanUtils.copyProperties(one,recordDTO);
        return recordDTO;
    }


    @Async
    @Override
    public void updateExperimentCommitNumber(Integer experimentId){
        Integer recordNum = userReExperimentMapper.getCountByExperimentId(experimentId);
        String bizCommitNumKey = RedisConstant.getBizCommitNumKey(experimentId);
        stringRedisTemplate.opsForValue().set(bizCommitNumKey, String.valueOf(recordNum));
        ExperimentMaster experimentMaster = experimentMasterMapper.selectExperimentMasterByExperimentId(experimentId);
        Integer courseNumber = achievementMapper.getCountByCourseId(experimentMaster.getCourseId());
        if(recordNum>=courseNumber*experimentMaster.getValve()){
            //到达人数，查看他的下一个实验是否已经解锁，如果未解锁则解锁
            ExperimentMaster nextExperimentMaster = experimentMasterMapper.getNextExperimentMaster(experimentId, experimentMaster.getCourseId());
            if (nextExperimentMaster.getExperimentStatus()==ExperimentStatusEnum.LOCK.getCode()){
                experimentService.unlock(nextExperimentMaster.getExperimentId());
                log.info("experiment id :{},now submit {},new experiment id:{} unlock",experimentId,recordNum,nextExperimentMaster.getExperimentId());
            }
        }

    }

    @Override
    public void initAllExperimentCommitNumber() {
        List<Integer> experimentMasterIdList = experimentMasterMapper.getExperimentMasterIdList(ExperimentStatusEnum.NORMAL.getCode());
        List<HashMap> allCountGroupByCourseId = userReExperimentMapper.getAllCountGroupByCourseId();
        //对已产生提交的实验ID进行提取，并将结果放置进缓存
        List<Integer> existList = allCountGroupByCourseId.stream().map((hashMap -> {
            Integer experiment_id = (Integer) hashMap.get("experiment_id");
            Long num = (Long) hashMap.get("num");
            String bizCommitNumKey = RedisConstant.getBizCommitNumKey(experiment_id);
            stringRedisTemplate.opsForValue().set(bizCommitNumKey, String.valueOf(num));
            return Integer.valueOf(experiment_id);
        })).collect(Collectors.toList());
        //从所有的ID中挑取未提交的实验ID，并将0结果放进缓存
        experimentMasterIdList.stream().forEach(id -> {
            if(!existList.contains(id)) {
                String bizCommitNumKey = RedisConstant.getBizCommitNumKey(id);
                stringRedisTemplate.opsForValue().set(bizCommitNumKey, String.valueOf(0));
            }
        });
    }

    @Override
    public List<RecordDTO> getRecordByUserIdAndCourseId(Integer userId, Integer CourseId) {
        List<ExperimentMaster> experimentMasters = experimentMasterMapper.selectExperimentMasterByCourseId(CourseId);
        if (experimentMasters==null){
            return null;
        }
        List<RecordDTO> list=new LinkedList<>();
        for(int i=0;i<experimentMasters.size();i++){
            Record record=userReExperimentMapper.selectUserReExperimentByExperimentIdAndUserId(experimentMasters.get(i).getExperimentId(),userId);
            if (record!=null){
                RecordDTO recordDTO = new RecordDTO();
                BeanUtils.copyProperties(record,recordDTO);
                recordDTO.setExperimentName(experimentMasters.get(i).getExperimentName());
                list.add(recordDTO);
            }
        }
        return list;
    }
}
